package com.bee.study.common;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @version 1.0.0
 * @Author yong.Mr
 * @data 2019-8-9
 */
@Service
public class BDRedis {

    @Resource
    private RedisTemplate<Object,Object> redisTemplate;

    @Resource
    private RedisConnectionFactory mConnectionFactory;

    private StringRedisTemplate stringRedisTemplate;

    @PostConstruct
    public void postInit(){
        stringRedisTemplate = new StringRedisTemplate(mConnectionFactory);
    }

    /**
     * 插入单个值
     * @param key       键
     * @param value     值
     */
    public void set(Object key ,Object value){
        // ValueOperations<Object, Object> objectObjectValueOperations，一个key 对一个Value 不能一个key对应多个值，
       //  如果多个值 需要用到ListOperations等等。
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 单个插入元素,并设置过期时间
     * @param key       键
     * @param value     值
     * @param timeout   有效期时长
     * @param unit      时间单位，TimeUnit
     */
    public void set(Object key , Object value, long timeout, TimeUnit unit){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        redisTemplate.opsForValue().set(key, value ,timeout,unit);
    }

    /**
     * 批量操作
     * 将map中键值对写入Redis
     * @param map   键值对数组，不为null
     */
    public void multiSet(Map<Object,Object> map){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        redisTemplate.opsForValue().multiSet(map);
    }

    /**
     * 如果键不存在，则插入键值对。键存在，不作处理，返回false
     * 该方法对应 Redis 的 SETNX
     * @param key       键，不可为空
     * @param value     值
     * @return
     */
    public Boolean setIfAdsent(Object key , Object value){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 只要map中的key有一个存在就返回false, 不作处理, 也不会插入
     * 且仅当所有键不存在时，将所有键值对存入Redis
     * @param map
     */
    public Boolean multiSetIfAbsent(Map<Object, Object> map){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().multiSetIfAbsent(map);
    }

    /**
     * 为键设定新值，并返回旧值
     * @param key   键，不可为空
     * @param value 新值
     * @return      返回旧值
     */
    public Object getAndSet(Object key, Object value){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().getAndSet(key, value);
    }

    /**
     * 获取指定键的值
     * @param key   键，不可为空
     */
    public Object get(Object key){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 根据list中的key批量获取value
     * 获取所有给定的键对应的值，List中值的顺序与键的顺序一一对应
     * 但是即使对应的key下面没有值，这个**value也会返回**，不过是null，
     * @param listKey
     */
    public List<Object> multiGet(List<Object> listKey){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().multiGet(listKey);
    }

    /**
     * 将指定的键对应的值加上一个整数
     * @param key
     * @param delta 增量，整数
     * @return 返回相加后的和值, 及相加之后的值，最终的值返回
     */
    public long increment(Object key,Long delta){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().increment(key,delta);
    }

    /**
     * 将指定的键对应的值加上一个浮点数
     * @param key
     * @param delta
     * @return 返回相加后的和值, 及相加之后的值，最终的值返回
     */
    public double increment(Object key,double delta){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 如果key已经存在并且是一个字符串，则该命令将该值追加到字符串的末尾。
     * 如果键不存在，则它被创建并设置为空字符串
     * @param key
     * @param value
     */
    public Integer append(Object key,String value){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.opsForValue().append(key, value);
    }

    /**
     * 获取对应key的value的长度
     * @param key
     */
    public Long size(Object key){
        // ValueOperations<Object, Object> objectObjectValueOperations，
       return redisTemplate.opsForValue().size(key);
    }

    public Long getExpire(Object key){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.getExpire(key);
    }

    /**
     * 根据key获取指定的时间，并且转换为指定的时间单位
     * @return
     */
    public Long getExpire(Object key, TimeUnit time){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.getExpire(key,time);
    }

    /**
     * 设置过期时间
     * @param key
     */
    public Boolean setExpire(Object key,long delaty, TimeUnit time){
        // ValueOperations<Object, Object> objectObjectValueOperations，
       return redisTemplate.expire(key, delaty, time);
    }

    /**
     * 判断当前key是否存在
     * @param key
     */
    public Boolean hashKey(Object key){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.hasKey(key);
    }
    /**
     * 删除指定的key
     * @param key
     */
    public Boolean delete(Object key){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.delete(key);
    }

    /**
     * 批量删除list中的所有值
     * @param keys
     */
    public Long delete(List<Object> keys){
        // ValueOperations<Object, Object> objectObjectValueOperations，
        return redisTemplate.delete(keys);
    }

    /**
     * 发送消息
     * @param message
     */
    public Long lpush(Object key,Object message){
        return redisTemplate.opsForList().leftPush(key, message);
    }

    /**
     * 向redis的某个key下面的list列表里面插入一个list列表，不会去重.
     * @param key
     * @param message
     */
    public Long lpushAll(Object key,List<Object> message){
        return redisTemplate.opsForList().leftPushAll(message);
    }

    /**
     * 获取消息,可以对消息进行监听，没有超过监听事件，则返回消息为null
     * rightPop：1.key,2.超时时间，3.超时时间类型
     * @return
     */
    public Object rpop(Object key){
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 从redis中取出某一个key下面的list列表，批量取
     * @param key 需要取的key值
     * @param start 从哪个位置开始取
     * @param end 结束的位置
     */
    public List<Object> rpopAll(Object key,Long start, Long end){
        return redisTemplate.opsForList().range(key, start, end);
    }

    // ##########################set类型#########################

    /**
     * 相指定key下面插入一个一个value，是在key的set集合中
     * @param key
     * @param value
     */
    public Long addSet(Object key,Object value){
        return redisTemplate.opsForSet().add(value);
    }

    /**
     *获取指定key下sey集合
     * @param key
     */
    public Set<Object> members(Object key){
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 移除指定key下面的元素，
     * @param key
     * @param value
     * @param value1
     */
    public Boolean members(Object key,Object value, Object value1){
        return redisTemplate.opsForSet().move(key, value, value);
    }
}

